<template>
  <div>
    <h1>Web Serial API方法</h1>
    <div class="serial-port">
      <button @click="connectToSerialPort">连接串口</button>
      <div>
        <input class="input-txt" type="text" v-model="serial_send_content" />
        <button @click="writable_input">写入</button>
      </div>
      <div>
        <button @click="closeSerialPort">关闭</button>
        <button @click="clear">清空</button>
      </div>
      <div>
        <button @click="startModel">初始化</button>
        <button @click="rtcModel">RTC模块</button>
        <button @click="adcModel">ADC模块</button>
        <button @click="frequencyModel">频率模块</button>
        <button @click="diModel">DI模块</button>
        <button @click="doModel">DO模块</button>
        <button @click="eepromModel">EEPROM模块</button>
        <button @click="ledModel">LED、KEY、屏幕</button>
        <button @click="cshModel">写入初始化参数</button>
        <button @click="closeSourceModel">关闭源</button>
      </div>
      <div>
        <div>本次返回的数据：{{ backData }}</div>
      </div>
      <hr />
      <div class="operation-record">
        <div v-for="(log, index) in operation_record_list" :key="index">
          {{ log.time }} ==> {{ log.content }}
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import dayjs from "dayjs";
import {
  initialization,
  RTCModel,
  ADCModel,
  FrequencyModel,
  DIModel,
  DOModel,
  EepromModel,
  LEDModel,
  CshModel,
  CloseSourceModel,
} from "../methods/sendDataList";

import { useRouter } from "vue-router";
const router  = useRouter();
console.log(router.options.routes);

onMounted(() => {
  console.log(dayjs().format("YYYY-MM-DD HH:mm:ss"));
  if ("serial" in navigator) {
    //   console.log("serial" in navigator);
    // TODO: 自动打开事件。目标器或警告用户端口可用。
    navigator.serial.addEventListener("connect", (e) => {
      console.log(e);
    });
    // 如果打开了串行端口，还会观察到流错误。
    navigator.serial.addEventListener("disconnect", (e) => {
      console.log(e);
    });

    navigator.serial.getPorts().then((ports) => {
      console.log(ports);
    });
  } else {
    console.log("当前为HTTP模式或者浏览器版本过低，不支持网页连接串口");
  }
});

const port = ref("");
const ports = ref([]);
const reader = ref("");
const writer = ref("");

const isSerialOpen = ref(false);
const isSerialClose = ref(false);

const connectToSerialPort = async () => {
  try {
    // 提示用户选择一个串口
    port.value = await navigator.serial.requestPort();

    // 获取用户之前授予该网站访问权限的所有串口。
    ports.value = await navigator.serial.getPorts();

    console.log(port.value, ports.value);
    // 等待串口打开
    await port.value.open({ baudRate: 115200 }).then(() => {
      isSerialOpen.value = true;
      isSerialClose.value = false;
      readData();
      // console.log("打开串口");
    });
  } catch (error) {
    // 处理连接串口出错的情况
    console.log("Error connecting to serial port:", error);
  }
};

let receivedData = ref([]); // 收到的数据
let packageTimeout = null; // 分包超时定时器

// 读取数据
const readData = async () => {
  while (isSerialOpen.value && port.value.readable) {
    reader.value = port.value.readable.getReader();
    // console.log(reader);
    // 监听来自串口的数据
    try {
      while (true) {
        const { value, done } = await reader.value.read();
        // console.log(value, done);
        const decoder = new TextDecoder();
        // 如果done为真，则串行端口已经关闭，或者没有更多的数据输入
        if (done) {
          const sendData = new TextDecoder().decode(value);
          console.log("串行端口已经关闭", sendData);
          reader.value.releaseLock();
          writer.value.releaseLock();
          break;
        }
        if (value) {
          //   console.log("返回内容backdata==》", value);
          // Uint8Array 转为数组
          // console.log(Array.from(value), value);

          // receivedData.value.push.apply(receivedData.value, Array.from(value));
          receivedData.value = [...receivedData.value, ...Array.from(value)]; // 追加收到的数据到 receivedData
          clearTimeout(packageTimeout); // 清除上一次的分包超时定时器
          packageTimeout = setTimeout(() => {
            handlePackageTimeout();
          }, 50); // 设置新的分包超时定时器
        }
      }
    } catch (error) {
      console.log(error);
    }
  }
};

// 处理分包超时逻辑
const handlePackageTimeout = () => {
  // 在此处处理分包超时逻辑
  // console.log("返回内容,分包超时==>", receivedData.value);
  hexStr(receivedData.value);
  receivedData.value = []; // 清空已收到的数据
};

const closeSerialPort = async () => {
  if (port.value) {
    isSerialOpen.value = false;
    await reader.value.cancel();
    await port.value.close();
  }
};

// 发送数据到串口
// 01 10 00 00 00 01 02 00 08 a7 96
const serial_send_content = ref("01 06 00 00 00 08 88 0C");
const isWrite = ref(true);

const writable_input = () => {
  writable(serial_send_content.value);
};

const writable = async (val) => {
  if (isSerialOpen.value) {
    writer.value = port.value.writable.getWriter();
    let data = await sendHex(val);
    console.log("写入内容，sendHex==》", data);
    if (isWrite.value) {
      await writer.value.write(data);
      // console.log(writer.value);
      adddLog(val);
    }
    writer.value.releaseLock();
  } else {
    alert("请先打开串口再发送数据");
  }
};

// 将发送的数据内容处理成hex格式
const sendHex = async (e) => {
  const value = e.replace(/\s+/g, "");
  if (/^[0-9A-Fa-f]+$/.test(value) && value.length % 2 === 0) {
    let data = [];
    for (let i = 0; i < value.length; i = i + 2) {
      data.push(parseInt(value.substring(i, i + 2), 16));
    }
    // await writeData(Uint8Array.from(data));
    // console.log(Uint8Array.from(data));
    isWrite.value = true;
    return Uint8Array.from(data);
  } else {
    // closeSerialPort();
    isWrite.value = false;
    console.log("HEX格式错误:" + e);
    adddLog("HEX格式错误:" + e);
  }
};

// 处理返回的数据
const backData = ref("");
const hexStr = async (val) => {
  // 十进制转为十六进制方法
  const hexArray = val.map((e) => {
    let hex = e.toString(16);
    return hex.length === 1 ? "0" + hex : hex;
  });
  // console.log(hexArray);
  const result = hexArray.map((item) => item.toUpperCase()).join(" ");
  backData.value = result;
  console.log("处理返回的数据==>", hexArray, result);
  // hexArray: ['01', '06', '00', '88', '01', '7c', '09', '91']
  // result: 01 06 00 88 01 7C 09 91
  backDataCRC(hexArray);
  // console.log(start_num.value);
  adddLog(result);

  // 匹配校验规则
  if (
    start_num.value === 3 ||
    start_num.value === 4 ||
    rtc_num.value === 3 ||
    rtc_num.value === 4 ||
    rtc_num.value === 5 ||
    adc_num.value === 2 ||
    adc_num.value === 3 ||
    adc_num.value === 4 ||
    frequency_num.value === 2 ||
    frequency_num.value === 3 ||
    frequency_num.value === 4 ||
    di_num.value === 2 ||
    di_num.value === 3 ||
    di_num.value === 4 ||
    do_num.value === 2 ||
    do_num.value === 3 ||
    do_num.value === 4 ||
    eeprom_num.value === 2 ||
    eeprom_num.value === 3 ||
    eeprom_num.value === 4 ||
    csh_num.value === 3 ||
    csh_num.value === 4 ||
    csh_num.value === 5 ||
    closeSource_num.value === 2
  ) {
    match_rules(hexArray);
  }

  // const hexArray = val
  //   .map((e) => {
  //     let hex = e.toString(16);
  //     if (hex.length < 2) hex = "0" + hex;
  //     return hex.toUpperCase();
  //   })
  //   .join(" ");
  // backData.value = hexArray;
  // console.log(hexArray);
};

const operation_record_list = ref([]);
// 添加日志
const adddLog = (e) => {
  let data = {
    time: dayjs().format("YYYY-MM-DD HH:mm:ss:SSS"),
    content: e,
  };
  operation_record_list.value.push(data);
};

// 清空
const clear = () => {
  operation_record_list.value = [];
};

// js中crc_modbus16校验计算
function calculateCRC16Modbus(val) {
  //   console.log("crc_modbus16校验计算==>", val);
  let e = val.split(" ").join("");
  const dataBytes = [];
  for (let i = 0; i < e.length; i += 2) {
    dataBytes.push(parseInt(e.substr(i, 2), 16));
  }

  let crc = 0xffff;
  const polynomial = 0xa001; // This is the polynomial x^16 + x^15 + x^2 + 1

  for (const byte of dataBytes) {
    crc ^= byte;
    for (let i = 0; i < 8; i++) {
      if (crc & 0x0001) {
        crc = ((crc >> 1) ^ polynomial) & 0xffff;
      } else {
        crc >>= 1;
      }
    }
  }
  let a = crc.toString(16).toUpperCase();
  a = a.length === 3 ? "0" + a : a;
  let data = {
    crc_data: a,
    g: a.substring(2, 4),
    d: a.substring(0, 2),
    g_10: parseInt(a.substring(2, 4), 16),
    d_10: parseInt(a.substring(0, 2), 16),
  };
  return data;
}

// 初始化
const start_num = ref(1);
const startModel = () => {
  if (isSerialOpen.value) {
    if (start_num.value <= 4) {
      // console.log(start_num.value);
      let send_data = initialization(start_num.value);
      let a = calculateCRC16Modbus(send_data);
      send_data = send_data + " " + a.g + " " + a.d;
      // console.log(send_data);
      writable(send_data);
      // 返回数据crc校验进行判断
      setTimeout(() => {
        if (isContinue.value) {
          start_num.value++;
          // console.log(start_num.value);
          startModel();
        }
      }, 500);
    } else {
      start_num.value = 1;
    }
  }
};

// RTC模块
const is_rtc = ref(true);
const rtc_num = ref(1);
const rtcModel = () => {
  is_rtc.value = true;
  if (isSerialOpen.value) {
    if (rtc_num.value <= 5) {
      console.log(rtc_num.value);
      let send_data = RTCModel(rtc_num.value);
      console.log(send_data);
      let a = calculateCRC16Modbus(send_data);
      send_data = send_data + " " + a.g + " " + a.d;
      // console.log(send_data);
      writable(send_data);
      // 返回数据crc校验进行判断
      // console.log("=============");
      setTimeout(() => {
        if (is_rtc.value) {
          if (isContinue.value) {
            rtc_num.value++;
            rtcModel();
          }
        } else {
          console.log("该板功能模块异常");
        }
      }, 500);
    } else {
      rtc_num.value = 1;
    }
  }
};

// ADC模块
const is_adc = ref(true);
const adc_num = ref(1);
const adcModel = () => {
  if (isSerialOpen.value) {
    if (adc_num.value <= 4) {
      let send_data = ADCModel(adc_num.value);
      let a = calculateCRC16Modbus(send_data);
      send_data = send_data + " " + a.g + " " + a.d;
      // console.log("send_data",send_data);
      writable(send_data);
      // 返回数据crc校验进行判断
      setTimeout(() => {
        if (is_adc.value) {
          if (isContinue.value) {
            adc_num.value++;
            adcModel();
          }
        }
      }, 500);
    } else {
      adc_num.value = 1;
    }
  }
};

// 频率模块
const is_pl = ref(true);
const frequency_num = ref(1);
const frequencyModel = () => {
  if (isSerialOpen.value) {
    if (frequency_num.value <= 4) {
      let send_data = FrequencyModel(frequency_num.value);
      let a = calculateCRC16Modbus(send_data);
      send_data = send_data + " " + a.g + " " + a.d;
      // console.log(send_data);
      writable(send_data);
      // 返回数据crc校验进行判断
      setTimeout(() => {
        if (is_pl.value) {
          if (isContinue.value) {
            frequency_num.value++;
            frequencyModel();
          }
        }
      }, 500);
    } else {
      frequency_num.value = 1;
    }
  }
};

// DI 模块
const is_di = ref(true);
const di_num = ref(1);
const diModel = () => {
  if (di_num.value <= 4) {
    let send_data = DIModel(di_num.value);
    let a = calculateCRC16Modbus(send_data);
    send_data = send_data + " " + a.g + " " + a.d;
    console.log(send_data);
    writable(send_data);
    // 返回数据crc校验进行判断
    setTimeout(() => {
      if (is_di.value) {
        if (isContinue.value) {
          di_num.value++;
          diModel();
        }
      }
    }, 500);
  } else {
    di_num.value = 1;
  }
};

// DO 模块
const is_do = ref(true);
const do_num = ref(1);
const doModel = () => {
  if (do_num.value <= 4) {
    let send_data = DOModel(do_num.value);
    let a = calculateCRC16Modbus(send_data);
    send_data = send_data + " " + a.g + " " + a.d;
    console.log(send_data);
    writable(send_data);
    // 返回数据crc校验进行判断
    setTimeout(() => {
      if (is_do.value) {
        if (isContinue.value) {
          do_num.value++;
          doModel();
        }
      }
    }, 500);
  } else {
    do_num.value = 1;
  }
};

// EEPROM模块
const is_eep = ref(true);
const eeprom_num = ref(1);
const eepromModel = () => {
  if (eeprom_num.value <= 4) {
    let send_data = EepromModel(eeprom_num.value);
    let a = calculateCRC16Modbus(send_data);
    send_data = send_data + " " + a.g + " " + a.d;
    console.log(send_data);
    writable(send_data);
    // 返回数据crc校验进行判断
    setTimeout(() => {
      if (is_eep.value) {
        if (isContinue.value) {
          eeprom_num.value++;
          eepromModel();
        }
      }
    }, 500);
  } else {
    eeprom_num.value = 1;
  }
};

// LED、KEY、屏幕
const ledModel = () => {
  let send_data = LEDModel();
  let a = calculateCRC16Modbus(send_data);
  send_data = send_data + " " + a.g + " " + a.d;
  console.log(send_data);
  writable(send_data);
};

// 写入初始化参数
const is_csh = ref(true);
const csh_num = ref(1);
const cshModel = () => {
  if (csh_num.value <= 5) {
    let send_data = CshModel(csh_num.value);
    let a = calculateCRC16Modbus(send_data);
    send_data = send_data + " " + a.g + " " + a.d;
    console.log(send_data);
    writable(send_data);
    // 返回数据crc校验进行判断
    setTimeout(() => {
      if (is_csh.value) {
        if (isContinue.value) {
          csh_num.value++;
          cshModel();
        }
      }
    }, 500);
  } else {
    csh_num.value = 1;
  }
};

// 关闭源
const closeSource_num = ref(1);
const closeSourceModel = () => {
  // console.log(closeSource_num.value);
  if (closeSource_num.value <= 2) {
    let send_data = CloseSourceModel(closeSource_num.value);
    let a = calculateCRC16Modbus(send_data);
    send_data = send_data + " " + a.g + " " + a.d;
    // console.log(send_data);
    writable(send_data);
    // 返回数据crc校验进行判断
    setTimeout(() => {
      if (isContinue.value) {
        closeSource_num.value++;
        closeSourceModel();
      }
    }, 500);
  } else {
    closeSource_num.value = 1;
    adddLog("退出测试，切断电源");
  }
};

// 返回的数据进行crc校验进行判断
const backDataCRC = (val) => {
  let a = val.map((item) => item.toUpperCase());
  let len = a.length;
  let x = a.slice(0, len - 2);
  let y = a.slice(len - 2, len);
  let z_crc = calculateCRC16Modbus(x.join(" "));
  //   console.log("返回的数据进行crc校验", a, x, y, z_crc);
  // console.log(
  //   "返回的数据进行crc校验",
  //   y,
  //   z_crc,
  //   y[0] === z_crc.g && y[1] === z_crc.d
  // );
};

// 匹配对应的校验方式
const isContinue = ref(true);
const match_rules = (val) => {
  console.log(val);
  let a = val.map((item) => item.toUpperCase());
  let len = a.length;
  let x = a.slice(0, len - 2);
  let y = a.slice(len - 2, len);
  console.log("匹配对应的校验方式==>", a);
  isContinue.value = false;
  // 1、测试结果为0XBB（模块异常）时，提示“该板XX功能异常”，并退出测试，切断电源。
  if (start_num.value === 3) {
    // isContinue.value = false;
    let b = x.slice(3);
    // console.log(b[0] + b[1] === "0000");
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        startModel();
      }, 500);
    }
  }
  if (start_num.value === 4) {
    let b = x.slice(3);
    // console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
      adddLog("初始化成功!");
    } else {
      // setTimeout(() => {
      //   startModel();
      // }, 1000);
      isContinue.value = true;
      console.log("初始化失败!");
      adddLog("初始化失败!");
    }
  }
  if (rtc_num.value === 3) {
    let b = x.slice(3);
    // console.log(b[0] + b[1] === "0000");
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        rtcModel();
      }, 500);
    }
  }
  if (rtc_num.value === 4) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      isContinue.value = true;
      is_rtc.value = false;
      rtc_num.value = 1;
      adddLog("该板功能RTC模块异常");
      closeSourceModel();
    }
  }
  if (rtc_num.value === 5) {
    let b = x.slice(3);
    // console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    }
    // if (b[0] + b[1] === "0001")
    else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
      console.log(`RTC模块,错误码为${b[1]}`);
    }
  }
  if (adc_num.value === 2) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        adcModel();
      }, 500);
    }
  }
  if (adc_num.value === 3) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能ADC模块异常");
      isContinue.value = true;
      is_adc.value = false;
      adc_num.value = 1;
      closeSourceModel();
    }
  }
  if (adc_num.value === 4) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      isContinue.value = true;
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (frequency_num.value === 2) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        frequencyModel();
      }, 500);
    }
  }
  if (frequency_num.value === 3) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能频率模块异常");
      isContinue.value = true;
      is_pl.value = false;
      frequency_num.value = 1;
      closeSourceModel();
    }
  }
  if (frequency_num.value === 4) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    }
    // if (b[0] + b[1] === "0001")
    else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (di_num.value === 2) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        diModel();
      }, 500);
    }
  }
  if (di_num.value === 3) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能DI模块异常");
      isContinue.value = true;
      is_di.value = false;
      di_num.value = 1;
      closeSourceModel();
    }
  }
  if (di_num.value === 4) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (do_num.value === 2) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        doModel();
      }, 500);
    }
  }
  if (do_num.value === 3) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能DO模块异常");
      isContinue.value = true;
      is_do.value = false;
      do_num.value = 1;
      closeSourceModel();
    }
  }
  if (do_num.value === 4) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (eeprom_num.value === 2) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        eepromModel();
      }, 500);
    }
  }
  if (eeprom_num.value === 3) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能EEPROM模块异常");
      isContinue.value = true;
      is_eep.value = false;
      eeprom_num.value = 1;
      closeSourceModel();
    }
  }
  if (eeprom_num.value === 4) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (csh_num.value === 3) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        cshModel();
      }, 500);
    }
  }
  if (csh_num.value === 4) {
    let b = x.slice(4);
    console.log(b[0]);
    if (b[0] === "AA") {
      isContinue.value = true;
    } else if (b[0] === "BB") {
      adddLog("该板功能写入初始化参数异常");
      isContinue.value = true;
      is_csh.value = false;
      csh_num.value = 1;
      closeSourceModel();
    }
  }
  if (csh_num.value === 5) {
    let b = x.slice(3);
    console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      isContinue.value = true;
      // adddLog("错误码为1，超时");
      adddLog(`错误码为${b[1]}`);
    }
  }
  if (closeSource_num.value === 2) {
    let b = x.slice(3);
    // console.log(b[0] + b[1]);
    if (b[0] + b[1] === "0000") {
      isContinue.value = true;
    } else {
      setTimeout(() => {
        closeSourceModel();
      }, 500);
    }
  }
};
</script>

<style lang="less" scoped>
.input-txt {
  width: 240px;
  height: 32px;
}
</style>